package br.com.JZSolution.domineduplex.rede;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;

import br.com.JZSolution.domineduplex.DomineDuplex;
import br.com.JZSolution.domineduplex.exception.TranferenciaRejeitadaException;
import br.com.JZSolution.domineduplex.gui.util.ComunicadorDeMensagens;
import br.com.JZSolution.domineduplex.modelo.Transferencia;
import br.com.JZSolution.domineduplex.rede.protocolo.ProtocoloEnvio;

public class Remetente extends Thread {
	
	private String ipDestino;
	private int portaDestino;
	private boolean pronto;
	private File arquivo;
	private boolean executando = true;
	private int totalEnviado = 0;
	private Transferencia transf = null;
	
	public Remetente(String ip,int porta , File arquivo) {
		this.ipDestino = ip;
		this.portaDestino = porta;
		this.pronto = false;
		this.arquivo = arquivo;
	}
	
	public void Iniciar(){
		validar();
		if (pronto)
			start();
	}
	
	private void validar(){
		//TODO Validar
		pronto = true;
	}
	
	public boolean isPronto() {
		return pronto;
	}
	
	@Override
	public void run() {
		System.out.println("Remetente Iniciado! IP= "+ipDestino +" Porta : "+portaDestino);
		BufferedInputStream bufferedInputStream = null;
		OutputStream outputStream = null;
		InputStream inputStream = null;
		Socket socket = null;
		try{
			socket = new Socket(ipDestino,portaDestino);
			System.out.println("Conectado");
			transf = new Transferencia(arquivo,"Y","Y");
			
			int bytesLidos = 0;
			
			inputStream = socket.getInputStream();
			outputStream = socket.getOutputStream();
			
			// Se o arquivo foi aceito então continua senão sai!
			ProtocoloEnvio protocolo = new ProtocoloEnvio();
			if (!protocolo.confirmarEnvio(outputStream, inputStream, arquivo)){
				throw new TranferenciaRejeitadaException();
			}	
			
			
			ativarContadorDeVelocidade();
			transf.setEstado(Transferencia.ATIVA);
			FileInputStream fis = new FileInputStream(arquivo);
			bufferedInputStream = new BufferedInputStream(fis);
			byte [] arrayLeitor = new byte[512];
			
			do{
				bytesLidos = bufferedInputStream.read(arrayLeitor);
				if (bytesLidos > 0){
					outputStream.write(arrayLeitor,0,bytesLidos);	
					outputStream.flush();
					totalEnviado += bytesLidos;
				}	
				
				transf.atualizarInterface(totalEnviado);
			} while ( bytesLidos != -1 && executando);
			
			transf.setEstado(Transferencia.CONCLUIDA_SUCESSO);
			
		}catch (TranferenciaRejeitadaException e) {
			ComunicadorDeMensagens.erro("A transferência não foi aceita.");
			if(transf != null){
				transf.setEstado(Transferencia.CANCELADA);
			}
			e.printStackTrace();
		}catch (UnknownHostException e) {
			ComunicadorDeMensagens.erro("Não foi possível enviar o arquivo para este usuário! Verifique se o endereço de destino está correto.");
			e.printStackTrace();
		}catch (ConnectException e) {
			ComunicadorDeMensagens.erro("Não foi possível enviar o arquivo! O destinatário não está conectado!");
			e.printStackTrace();
		}catch (SocketException e) {
			ComunicadorDeMensagens.erro("Ocorreu um erro na transferência do arquivo, tente novamente.");
			if(transf != null){
				DomineDuplex.getInstance().avisarFimDeTransferencia(transf);
				transf.setEstado(Transferencia.CONCLUIDA_FALHA);
			}	
			e.printStackTrace();
		}catch (Exception e) {
			if(transf != null){
				transf.setEstado(Transferencia.CANCELADA);
			}
			e.printStackTrace();
		}finally{
			if(transf != null){
				DomineDuplex.getInstance().avisarFimDeTransferencia(transf);
			}	
			//Fechando o stream
			if(bufferedInputStream != null)
				try{bufferedInputStream.close();}catch (Exception e) {}
			if(outputStream != null)
				try{outputStream.close();}catch (Exception e) {}
			if(inputStream != null)
				try{inputStream.close();}catch (Exception e) {}
			if(socket != null)
				try{socket.close();}catch (Exception e) {}
				
			executando = false;
			transf.setVelocidade(0);
			System.out.println("Remetente Terminado");
		}
	}
	
	
	private void ativarContadorDeVelocidade() {
		Thread t = new Thread(){
			public void run() {
				long temporizador = 0;
				final long sleep = 500;
				long ultimosBytes = 0;
				long inicioBytes = 0;
				
				while(executando){
					try{
						ultimosBytes = totalEnviado;
						if(temporizador == sleep * 10 || temporizador == 0){
							float velocidade = ultimosBytes - inicioBytes;
							velocidade = (velocidade / (sleep * 10));// KBps 
							//avisa a interface
							transf.setVelocidade(velocidade);

							inicioBytes = totalEnviado;
							temporizador = 0;
						}
						Thread.sleep(sleep);
						temporizador += sleep;
					}catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		};	
		t.start();
	}

	public String getIpDestino() {
		return ipDestino;
	}
	public void setIpDestino(String ipDestino) {
		this.ipDestino = ipDestino;
	}
	public int getPortaDestino() {
		return portaDestino;
	}
	public void setPortaDestino(int portaDestino) {
		this.portaDestino = portaDestino;
	}
	public void setExecutando(boolean executando) {
		this.executando = executando;
	}
}
